// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CONTENT_PPAPI_PLUGIN_PPAPI_THREAD_H_
#define CONTENT_PPAPI_PLUGIN_PPAPI_THREAD_H_

#include <stdint.h>

#include <map>
#include <memory>
#include <string>

#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/metrics/field_trial.h"
#include "base/process/process.h"
#include "base/scoped_native_library.h"
#include "build/build_config.h"
#include "components/variations/child_process_field_trial_syncer.h"
#include "content/child/child_thread_impl.h"
#include "content/public/common/pepper_plugin_info.h"
#include "ppapi/c/pp_module.h"
#include "ppapi/c/trusted/ppp_broker.h"
#include "ppapi/proxy/connection.h"
#include "ppapi/proxy/plugin_dispatcher.h"
#include "ppapi/proxy/plugin_globals.h"
#include "ppapi/proxy/plugin_proxy_delegate.h"

#if defined(OS_WIN)
#include "base/win/scoped_handle.h"
#endif

namespace base {
class CommandLine;
class FilePath;
}

namespace discardable_memory {
class ClientDiscardableSharedMemoryManager;
}

namespace IPC {
struct ChannelHandle;
}

namespace content {

class PpapiBlinkPlatformImpl;

#if defined(COMPILER_MSVC)
// See explanation for other RenderViewHostImpl which is the same issue.
#pragma warning(push)
#pragma warning(disable : 4250)
#endif

class PpapiThread : public ChildThreadImpl,
                    public ppapi::proxy::PluginDispatcher::PluginDelegate,
                    public ppapi::proxy::PluginProxyDelegate,
                    public base::FieldTrialList::Observer {
public:
    PpapiThread(const base::CommandLine& command_line, bool is_broker);
    ~PpapiThread() override;
    void Shutdown() override;

private:
    // Make sure the enum list in tools/histogram/histograms.xml is updated with
    // any change in this list.
    enum LoadResult {
        LOAD_SUCCESS,
        LOAD_FAILED,
        ENTRY_POINT_MISSING,
        INIT_FAILED,
        FILE_MISSING,
        // NOTE: Add new values only immediately above this line.
        LOAD_RESULT_MAX // Boundary value for UMA_HISTOGRAM_ENUMERATION.
    };

    // ChildThread overrides.
    bool Send(IPC::Message* msg) override;
    bool OnControlMessageReceived(const IPC::Message& msg) override;
    void OnChannelConnected(int32_t peer_pid) override;

    // PluginDispatcher::PluginDelegate implementation.
    std::set<PP_Instance>* GetGloballySeenInstanceIDSet() override;
    base::SingleThreadTaskRunner* GetIPCTaskRunner() override;
    base::WaitableEvent* GetShutdownEvent() override;
    IPC::PlatformFileForTransit ShareHandleWithRemote(
        base::PlatformFile handle,
        base::ProcessId peer_pid,
        bool should_close_source) override;
    base::SharedMemoryHandle ShareSharedMemoryHandleWithRemote(
        const base::SharedMemoryHandle& handle,
        base::ProcessId remote_pid) override;
    uint32_t Register(ppapi::proxy::PluginDispatcher* plugin_dispatcher) override;
    void Unregister(uint32_t plugin_dispatcher_id) override;

    // PluginProxyDelegate.
    // SendToBrowser() is intended to be safe to use on another thread so
    // long as the main PpapiThread outlives it.
    IPC::Sender* GetBrowserSender() override;
    std::string GetUILanguage() override;
    void PreCacheFontForFlash(const void* logfontw) override;
    void SetActiveURL(const std::string& url) override;
    PP_Resource CreateBrowserFont(ppapi::proxy::Connection connection,
        PP_Instance instance,
        const PP_BrowserFont_Trusted_Description& desc,
        const ppapi::Preferences& prefs) override;

    // Message handlers.
    void OnLoadPlugin(const base::FilePath& path,
        const ppapi::PpapiPermissions& permissions);
    void OnCreateChannel(base::ProcessId renderer_pid,
        int renderer_child_id,
        bool incognito);
    void OnSetNetworkState(bool online);
    void OnCrash();
    void OnHang();

    // base::FieldTrialList::Observer:
    void OnFieldTrialGroupFinalized(const std::string& trial_name,
        const std::string& group_name) override;

    // Sets up the channel to the given renderer. If |renderer_pid| is
    // base::kNullProcessId, the channel is set up to the browser. On success,
    // returns true and fills the given ChannelHandle with the information from
    // the new channel.
    bool SetupChannel(base::ProcessId renderer_pid,
        int renderer_child_id,
        bool incognito,
        IPC::ChannelHandle* handle);

    // Sets up the name of the plugin for logging using the given path.
    void SavePluginName(const base::FilePath& path);

    void ReportLoadResult(const base::FilePath& path, LoadResult result);

    // Reports |error| to UMA when plugin load fails.
    void ReportLoadErrorCode(const base::FilePath& path,
        const base::NativeLibraryLoadError& error);

    // Reports time to load the plugin.
    void ReportLoadTime(const base::FilePath& path,
        const base::TimeDelta load_time);

    // True if running in a broker process rather than a normal plugin process.
    bool is_broker_;

    base::ScopedNativeLibrary library_;

    ppapi::PpapiPermissions permissions_;

    // Global state tracking for the proxy.
    ppapi::proxy::PluginGlobals plugin_globals_;

    // Storage for plugin entry points.
    PepperPluginInfo::EntryPoints plugin_entry_points_;

    // Callback to call when a new instance connects to the broker.
    // Used only when is_broker_.
    PP_ConnectInstance_Func connect_instance_func_;

    // Local concept of the module ID. Some functions take this. It's necessary
    // for the in-process PPAPI to handle this properly, but for proxied it's
    // unnecessary. The proxy talking to multiple renderers means that each
    // renderer has a different idea of what the module ID is for this plugin.
    // To force people to "do the right thing" we generate a random module ID
    // and pass it around as necessary.
    PP_Module local_pp_module_;

    // See Dispatcher::Delegate::GetGloballySeenInstanceIDSet.
    std::set<PP_Instance> globally_seen_instance_ids_;

    // The PluginDispatcher instances contained in the map are not owned by it.
    std::map<uint32_t, ppapi::proxy::PluginDispatcher*> plugin_dispatchers_;
    uint32_t next_plugin_dispatcher_id_;

    // The BlinkPlatformImpl implementation.
    std::unique_ptr<PpapiBlinkPlatformImpl> blink_platform_impl_;

#if defined(OS_WIN)
    // Caches the handle to the peer process if this is a broker.
    base::win::ScopedHandle peer_handle_;
#endif

    variations::ChildProcessFieldTrialSyncer field_trial_syncer_;

    std::unique_ptr<discardable_memory::ClientDiscardableSharedMemoryManager>
        discardable_shared_memory_manager_;

    DISALLOW_IMPLICIT_CONSTRUCTORS(PpapiThread);
};

#if defined(COMPILER_MSVC)
#pragma warning(pop)
#endif

} // namespace content

#endif // CONTENT_PPAPI_PLUGIN_PPAPI_THREAD_H_
